home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / WASTE 1.2 Distribution / WASTE 1.2 / WEBirthDeath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-20  |  20.3 KB  |  806 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEBirthDeath.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Creation and Destruction, Standard Procs, etc.
  6.  *
  7.  *  Copyright (c) 1993-1996 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. #if GENERATINGCFM
  18. #ifndef __CODEFRAGMENTS__
  19. #include <CodeFragments.h>
  20. #endif
  21. #endif
  22.  
  23. const Point kOneToOneScaling = { 1, 1 };
  24.  
  25. // static variables
  26.  
  27. static WEDrawTextUPP        _weStdDrawTextProc = nil;
  28. static WEPixelToCharUPP        _weStdPixelToCharProc = nil;
  29. static WECharToPixelUPP        _weStdCharToPixelProc = nil;
  30. static WELineBreakUPP        _weStdLineBreakProc = nil;
  31. static WEWordBreakUPP        _weStdWordBreakProc = nil;
  32. static WECharByteUPP        _weStdCharByteProc = nil;
  33. static WECharTypeUPP        _weStdCharTypeProc = nil;
  34. static WEClickLoopUPP        _weStdClickLoopProc = nil;
  35. static WEHiliteDropAreaUPP    _weStdHiliteDropAreaProc = nil;
  36.  
  37. pascal void _WEStdDrawText(Ptr pText, SInt32 textLength, Fixed slop,
  38.                 JustStyleCode styleRunPosition, WEHandle hWE)
  39. {
  40. #pragma unused(hWE)
  41.     DrawJustified(pText, textLength, slop, styleRunPosition,
  42.           kOneToOneScaling, kOneToOneScaling);
  43. }
  44.  
  45. pascal SInt32 _WEStdPixelToChar(Ptr pText, SInt32 textLength, Fixed slop,
  46.                 Fixed *width, WEEdge *edge, JustStyleCode styleRunPosition,
  47.                 Fixed hPos, WEHandle hWE)
  48. {
  49. #pragma unused(hPos, hWE)
  50.     Fixed lastWidth;
  51.     SInt32 offset;
  52.  
  53.     lastWidth = *width;
  54.     offset = PixelToChar(pText, textLength, slop, lastWidth, (Boolean *) edge,
  55.         width, styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  56.  
  57.     // round width to nearest integer value
  58.     // (this is supposed to fix an incompatibility with the WorldScript Power Adapter)
  59.     *width = (*width + 0x00008000) & 0xFFFF0000;
  60.  
  61.     return offset;
  62. }
  63.  
  64. pascal SInt16 _WEStdCharToPixel(Ptr pText, SInt32 textLength, Fixed slop,
  65.                 SInt32 offset, SInt16 direction, JustStyleCode styleRunPosition,
  66.                 SInt32 hPos, WEHandle hWE)
  67. {
  68. #pragma unused(hPos, hWE)
  69.     return CharToPixel(pText, textLength, slop, offset, direction,
  70.             styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  71. }
  72.  
  73. pascal StyledLineBreakCode _WEStdLineBreak(Ptr pText, SInt32 textLength,
  74.                 SInt32 textStart, SInt32 textEnd, Fixed *textWidth,
  75.                 SInt32 *textOffset, WEHandle hWE)
  76. {
  77. #pragma unused(hWE)
  78.     return StyledLineBreak(pText, textLength, textStart, textEnd, 0, textWidth,
  79.                 textOffset);
  80. }
  81.  
  82. pascal void _WEStdWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  83.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  84.                 WEHandle hWE)
  85. {
  86. #pragma unused(hWE)
  87.     FindWordBreaks(pText, textLength, offset, (Boolean) edge, nil, breakOffsets, script);
  88. }
  89.  
  90. pascal SInt16 _WEStdCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  91.                 WEHandle hWE)
  92. {
  93. #pragma unused(hWE)
  94.     return CharacterByteType(pText, textOffset, script);
  95. }
  96.  
  97. pascal SInt16 _WEStdCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  98.                 WEHandle hWE)
  99. {
  100. #pragma unused(hWE)
  101.     return CharacterType(pText, textOffset, script);
  102. }
  103.  
  104. //    _WEScriptToFont, _WEOldWordBreak, _WEOldCharByte and _WEOldCharType
  105. //    are only needed to support version 7.0 / 7.0.1 of MacOS;
  106. //    PowerPC code doesn't need them as PowerPC machines need
  107. //    version 7.1.2 or later anyway.
  108.  
  109. #if ! (SystemSevenFiveOrLater || GENERATINGPOWERPC)
  110.  
  111. pascal SInt16 _WEScriptToFont(ScriptCode script)
  112. {
  113.     // given an explicit script code, return the first font ID in the corresponding range
  114.     // for an explanation of the formula given below, see IM: Text, page B-8
  115.  
  116.     if (script == smRoman)
  117.         return 2;
  118.     else if ((script > smRoman) && (script <= smUninterp))
  119.         return (0x3E00 + 0x200 * script);
  120.     else
  121.         return systemFont;    // unknown script code (?)
  122. }
  123.  
  124. pascal void _WEOldWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  125.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  126.                 WEHandle hWE)
  127. {
  128.     GrafPtr savePort, tempPort;
  129.     SInt16 saveFont;
  130.  
  131.     // the old (now obsolete) FindWord routine gets an implicit script parameter through
  132.     // the current graphics port txFont field, so first of all we must have a valid port
  133.     GetPort(&savePort);
  134.     tempPort = (*hWE)->port;
  135.     SetPort(tempPort);
  136.  
  137.     // then set the txFont field to a font number in the specified script range
  138.     saveFont = tempPort->txFont;
  139.     TextFont(_WEScriptToFont(script));
  140.  
  141.     // call _FindWord
  142.     FindWord(pText, textLength, offset, (Boolean)edge, nil, breakOffsets);
  143.  
  144.     // restore font and port
  145.     TextFont(saveFont);
  146.     SetPort(savePort);
  147.  
  148. }
  149.  
  150. pascal SInt16 _WEOldCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  151.                 WEHandle hWE)
  152. {
  153.     GrafPtr savePort, tempPort;
  154.     SInt16 saveFont;
  155.     SInt16 retVal;
  156.  
  157.     // the old (now obsolete) CharByte routine gets an implicit script parameter through
  158.     // the current graphics port txFont field, so first of all we must have a valid port
  159.     GetPort(&savePort);
  160.     tempPort = (*hWE)->port;
  161.     SetPort(tempPort);
  162.  
  163.     // then set the txFont field to a font number in the specified script range
  164.     saveFont = tempPort->txFont;
  165.     TextFont(_WEScriptToFont(script));
  166.  
  167.     // call _CharByte
  168.     retVal = CharByte(pText, textOffset);
  169.  
  170.     // restore font and port
  171.     TextFont(saveFont);
  172.     SetPort(savePort);
  173.  
  174.     return retVal;
  175. }
  176.  
  177. pascal SInt16 _WEOldCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  178.                 WEHandle hWE)
  179. {
  180.     GrafPtr savePort, tempPort;
  181.     SInt16 saveFont;
  182.     SInt16 retVal;
  183.  
  184.     // the old (now obsolete) CharType routine gets an implicit script parameter through
  185.     // the current graphics port txFont field, so first of all we must have a valid port
  186.     GetPort(&savePort);
  187.     tempPort = (*hWE)->port;
  188.     SetPort(tempPort);
  189.  
  190.     // then set the txFont field to a font number in the specified script range
  191.     saveFont = tempPort->txFont;
  192.     TextFont(_WEScriptToFont(script));
  193.  
  194.     // call _CharType
  195.     retVal = CharType(pText, textOffset);
  196.  
  197.     // restore font and port
  198.     TextFont(saveFont);
  199.     SetPort(savePort);
  200.  
  201.     return retVal;
  202.  
  203. }
  204.  
  205. #endif
  206.  
  207. pascal Boolean _WEStdClickLoop(WEHandle hWE)
  208. {
  209.     WEPtr pWE = *hWE;        // assume WE record is already locked
  210.     Point mouseLoc;
  211.     SInt32 currentOffset;
  212.     SInt32 maxOffset;
  213.     SInt32 vDelta = 0;
  214.     SInt32 hDelta = 0;
  215.  
  216.     // do nothing if auto-scroll is disabled or if we're inactive
  217.     if (!BTST(pWE->features, weFAutoScroll) || !BTST(pWE->flags, weFActive))
  218.         return true;
  219.  
  220.     // get current mouse location, in local coords
  221.     // we can safely assume the graphics port is set up correctly
  222.     GetMouse(&mouseLoc);
  223.  
  224.     // HANDLE VERTICAL AUTOSCROLL
  225.     currentOffset = pWE->viewRect.top - pWE->destRect.top;
  226.     maxOffset = (pWE->destRect.bottom - pWE->destRect.top) - (pWE->viewRect.bottom - pWE->viewRect.top);
  227.  
  228.     // is the mouse below the view rect?
  229.     if (mouseLoc.v > pWE->viewRect.bottom)
  230.     {
  231.         // is there anything hidden below the view rect?
  232.         if (currentOffset < maxOffset)
  233.         {
  234.             // then scroll down: calculate the scroll delta
  235.             vDelta = pWE->viewRect.bottom - mouseLoc.v;
  236.  
  237.             // pin the new vertical offset to the bottom of the dest rectangle
  238.             if (vDelta < (currentOffset - maxOffset))
  239.                 vDelta = currentOffset - maxOffset;
  240.  
  241.             // never scroll by more than kMaxScrollDelta pixels
  242.             if (vDelta < -kMaxScrollDelta)
  243.                 vDelta = -kMaxScrollDelta;
  244.         }
  245.     }
  246.  
  247.     // is the mouse above the view rect?
  248.     else if (mouseLoc.v < pWE->viewRect.top)
  249.     {
  250.         // is there anything hidden above the view rect?
  251.         if (currentOffset > 0)
  252.         {
  253.             // then scroll up: calculate the scroll delta
  254.             vDelta = pWE->viewRect.top - mouseLoc.v;
  255.  
  256.             // pin the new vertical offset to the top of the dest rectangle
  257.             if (vDelta > currentOffset)
  258.                 vDelta = currentOffset;
  259.  
  260.             // never scroll by more than kMaxScrollDelta pixels
  261.             if (vDelta > kMaxScrollDelta)
  262.                 vDelta = kMaxScrollDelta;
  263.         }
  264.     }
  265.  
  266.     // HANDLE HORIZONTAL AUTOSCROLL
  267.     currentOffset = pWE->viewRect.left - pWE->destRect.left;
  268.     maxOffset = (pWE->destRect.right - pWE->destRect.left) - (pWE->viewRect.right - pWE->viewRect.left);
  269.  
  270.     // is the mouse to the right of the view rect?
  271.     if (mouseLoc.h > pWE->viewRect.right)
  272.     {
  273.         // is there anything hidden to the right of the view rect?
  274.         if (currentOffset < maxOffset)
  275.         {
  276.             // then scroll right: calculate the scroll delta
  277.             hDelta = pWE->viewRect.right - mouseLoc.h;
  278.  
  279.             // pin the new vertical offset to the rightmost edge
  280.             // of the dest rectangle
  281.             if (hDelta < (currentOffset - maxOffset))
  282.                 hDelta = currentOffset - maxOffset;
  283.  
  284.             // never scroll by more than kMaxScrollDelta pixels
  285.             if (hDelta < -kMaxScrollDelta)
  286.                 hDelta = -kMaxScrollDelta;
  287.         }
  288.     }
  289.  
  290.     // is the mouse to the left of the view rect?
  291.     else if (mouseLoc.h < pWE->viewRect.left)
  292.     {
  293.         // is there anything hidden to the left of the view rect?
  294.         if (currentOffset > 0)
  295.         {
  296.             // then scroll up: calculate the scroll delta
  297.             hDelta = pWE->viewRect.left - mouseLoc.h;
  298.  
  299.             // pin the new horizontal offset to the leftmost edge
  300.             // of the dest rectangle
  301.             if (hDelta > currentOffset)
  302.                 hDelta = currentOffset;
  303.  
  304.             // never scroll by more than kMaxScrollDelta pixels
  305.             if (hDelta > kMaxScrollDelta)
  306.                 hDelta = kMaxScrollDelta;
  307.         }
  308.     }
  309.  
  310.     if ((vDelta != 0) || (hDelta != 0))
  311.     {
  312.         // do the scroll
  313.         WEScroll(hDelta, vDelta, hWE);
  314.  
  315.         // notify our client we have scrolled the text
  316.         if (pWE->scrollProc != nil)
  317.         {
  318.             CallWEScrollProc(hWE, pWE->scrollProc);
  319.         }
  320.     }
  321.  
  322.     return true;
  323. }
  324.  
  325. pascal OSErr _WEStdHiliteDropArea(DragReference drag, Boolean hiliteFlag, WEHandle hWE)
  326. {
  327.     WEPtr pWE = *hWE;        // assume WE record is already locked
  328.     RgnHandle tmpRgn;
  329.     OSErr err;
  330.  
  331.     if (hiliteFlag)
  332.     {
  333.         tmpRgn = NewRgn();
  334.         CopyRgn(pWE->viewRgn, tmpRgn);
  335.         InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
  336.         err = ShowDragHilite(drag, tmpRgn, true);
  337.         DisposeRgn(tmpRgn);
  338.     }
  339.     else
  340.     {
  341.         err = HideDragHilite(drag);
  342.     }
  343.     return err;
  344. }
  345.  
  346. pascal OSErr _WERegisterWithTSM(WEHandle hWE)
  347. {
  348.     WEPtr pWE = *hWE;    // assume WE record is already locked
  349.     InterfaceTypeList typeList;
  350.     OSErr err;
  351.  
  352.     // do nothing if the Text Services Manager isn't available
  353.     if (BTST(pWE->flags, weFHasTextServices))
  354.     {
  355.         typeList[0] = kTextService;
  356.         if ((err = NewTSMDocument(1, typeList, &pWE->tsmReference, (SInt32) hWE)) != noErr)
  357.         {
  358.             // we don't consider it an error if our client application isn't TSM-aware
  359.             if (err != tsmNeverRegisteredErr)
  360.             {
  361.                 goto cleanup;
  362.             }
  363.         }
  364.     }
  365.  
  366.     // clear result code
  367.     err = noErr;
  368.  
  369. cleanup:
  370.     // return result code
  371.     return err;
  372. }
  373.  
  374. pascal void _WESetStandardHooks(WEHandle hWE)
  375. {
  376.     WEPtr pWE;
  377.  
  378.     // the first time we're called, create routine descriptors
  379.     if (_weStdDrawTextProc == nil)
  380.     {
  381.         _weStdDrawTextProc = NewWEDrawTextProc(_WEStdDrawText);
  382.         _weStdPixelToCharProc = NewWEPixelToCharProc(_WEStdPixelToChar);
  383.         _weStdCharToPixelProc = NewWECharToPixelProc(_WEStdCharToPixel);
  384.         _weStdLineBreakProc = NewWELineBreakProc(_WEStdLineBreak);
  385.  
  386. #if ! (SystemSevenFiveOrLater || GENERATINGPOWERPC)
  387.  
  388.         if (GetScriptManagerVariable(smVersion) < 0x0710)
  389.         {
  390.             // pre-7.1 version of the Script Manager: must use old hooks
  391.             _weStdWordBreakProc = NewWEWordBreakProc(_WEOldWordBreak);
  392.             _weStdCharByteProc = NewWECharByteProc(_WEOldCharByte);
  393.             _weStdCharTypeProc = NewWECharTypeProc(_WEOldCharType);
  394.         }
  395.         else
  396. #endif
  397.         {
  398.             // Script Manager version 7.1 or newer
  399.             _weStdWordBreakProc = NewWEWordBreakProc(_WEStdWordBreak);
  400.             _weStdCharByteProc = NewWECharByteProc(_WEStdCharByte);
  401.             _weStdCharTypeProc = NewWECharTypeProc(_WEStdCharType);
  402.         }
  403.  
  404.         _weStdClickLoopProc = NewWEClickLoopProc(_WEStdClickLoop);
  405.         _weStdHiliteDropAreaProc = NewWEHiliteDropAreaProc(_WEStdHiliteDropArea);
  406.  
  407.     } // if called for the first time
  408.  
  409.     // replace null hook fields with the addresses of the standard hooks
  410.  
  411.     pWE = *hWE;
  412.  
  413.     // replace null hook fields with the addresses of the standard hooks
  414.  
  415.     if (pWE->drawTextHook == nil)
  416.         pWE->drawTextHook = _weStdDrawTextProc;
  417.  
  418.     if (pWE->pixelToCharHook == nil)
  419.         pWE->pixelToCharHook = _weStdPixelToCharProc;
  420.  
  421.     if (pWE->charToPixelHook == nil)
  422.         pWE->charToPixelHook = _weStdCharToPixelProc;
  423.  
  424.     if (pWE->lineBreakHook == nil)
  425.         pWE->lineBreakHook = _weStdLineBreakProc;
  426.  
  427.     if (pWE->wordBreakHook == nil)
  428.         pWE->wordBreakHook = _weStdWordBreakProc;
  429.  
  430.     if (pWE->charByteHook == nil)
  431.         pWE->charByteHook = _weStdCharByteProc;
  432.  
  433.     if (pWE->charTypeHook == nil)
  434.         pWE->charTypeHook = _weStdCharTypeProc;
  435.  
  436.     if (pWE->clickLoop == nil)
  437.         pWE->clickLoop = _weStdClickLoopProc;
  438.  
  439.     if (pWE->hiliteDropAreaHook == nil)
  440.         pWE->hiliteDropAreaHook = _weStdHiliteDropAreaProc;
  441. }
  442.  
  443. pascal OSErr WENew(const LongRect *destRect, const LongRect *viewRect, UInt32 features, WEHandle *hWE)
  444. {
  445.     WEPtr pWE = nil;
  446.     UInt32 allocFlags = kAllocClear;
  447.     SInt32 response;
  448.     Rect r;
  449.     OSErr err;
  450.  
  451.     // allocate the WE record
  452.     if ((err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE)) != noErr)
  453.     {
  454.         goto cleanup;
  455.     }
  456.  
  457.     // lock it down
  458.     HLock((Handle)*hWE);
  459.     pWE = **hWE;
  460.  
  461.     // get active port
  462.     GetPort(&pWE->port);
  463.  
  464.     // determine whether temporary memory should be used for data structures
  465.     if (BTST(features, weFUseTempMem))
  466.     {
  467.         allocFlags += kAllocTemp;
  468.     }
  469.  
  470.     // allocate the text handle (initially empty)
  471.     if ((err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText)) != noErr)
  472.     {
  473.         goto cleanup;
  474.     }
  475.  
  476.     // allocate the line array
  477.     if ((err = _WEAllocate(2 * sizeof(LineRec), allocFlags, (Handle *)&pWE->hLines)) != noErr)
  478.     {
  479.         goto cleanup;
  480.     }
  481.  
  482.     // allocate the style table
  483.     if ((err = _WEAllocate(sizeof(StyleTableElement), allocFlags, (Handle *)&pWE->hStyles)) != noErr)
  484.     {
  485.         goto cleanup;
  486.     }
  487.  
  488.     // allocate the run array
  489.     if ((err = _WEAllocate(2 * sizeof(RunArrayElement), allocFlags, (Handle *)&pWE->hRuns)) != noErr)
  490.     {
  491.         goto cleanup;
  492.     }
  493.  
  494.     // check for the presence of various system software features
  495.     // determine whether Color Quickdraw is available
  496.     if ((Gestalt(gestaltQuickdrawVersion, &response) == noErr) && (response >= gestalt8BitQD))
  497.     {
  498.         BSET(pWE->flags, weFHasColorQD);
  499.     }
  500.  
  501.     // determine whether the Drag Manager is available
  502.     if ((Gestalt(gestaltDragMgrAttr, &response) == noErr) && BTST(response, gestaltDragMgrPresent))
  503.     {
  504. #if GENERATINGCFM
  505.         if ((UInt32) NewDrag != kUnresolvedCFragSymbolAddress)
  506. #endif
  507.             BSET(pWE->flags, weFHasDragManager);
  508.  
  509.         // determine whether translucent drags are available
  510.         if (BTST(response, 3))
  511.         {
  512. #if GENERATINGCFM
  513.             // uncomment the following line as soon as Drag.h
  514.             // defines SetDragImage
  515.             //if ((UInt32) SetDragImage != kUnresolvedCFragSymbolAddress)
  516. #endif
  517.                 BSET(pWE->flags, weFHasTranslucentDrags);
  518.         }
  519.     }
  520.  
  521.     // determine whether the Text Services manager is available
  522.     if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
  523.     {
  524.         BSET(pWE->flags, weFHasTextServices);
  525.     }
  526.  
  527.     // determine if there are any non-Roman scripts enabled
  528.     if (GetScriptManagerVariable(smEnabled) > 1)
  529.     {
  530.         BSET(pWE->flags, weFNonRoman);
  531.  
  532.         // determine whether a double-byte script is installed
  533.         if (GetScriptManagerVariable(smDoubleByte) != 0)
  534.         {
  535. #if GENERATING68K
  536.             BSET(pWE->flags, weFDoubleByte);    // the WorldScript Power Adapter breaks this :-(
  537. #else
  538.             ScriptCode script;
  539.             for ( script = smRoman; script <= smKlingon; script++ )
  540.             {
  541.                 if (GetScriptVariable(script, smEnabled) &&
  542.                     ((GetScriptVariable(script, smScriptFlags) & smsfSingByte) == 0))
  543.                 {
  544.                     BSET(pWE->flags, weFDoubleByte);
  545.                     break;
  546.                 }
  547.             }
  548. #endif
  549.         }
  550.  
  551.         // determine whether a bidirectional script is installed
  552.         if (GetScriptManagerVariable(smBidirect) != 0)
  553.         {
  554.             BSET(pWE->flags, weFBidirectional);
  555.  
  556.             // should we use a dual caret?
  557.             if ((GetScriptManagerVariable(smGenFlags) & smfDualCaret) != 0)
  558.             {
  559.                 BSET(pWE->flags, weFUseDualCaret);
  560.             }
  561.         }
  562.     }
  563.  
  564.     // initialize miscellaneous fields of the WE record
  565.     pWE->nLines = 1;
  566.     pWE->nStyles = 1;
  567.     pWE->nRuns = 1;
  568.     pWE->viewRect = *viewRect;
  569.     pWE->destRect = *destRect;
  570.     pWE->features = features;
  571.     pWE->tsmAreaStart = kInvalidOffset;
  572.     pWE->tsmAreaEnd = kInvalidOffset;
  573.     pWE->dragCaretOffset = kInvalidOffset;
  574.  
  575.     // initialize hook fields with the addresses of the standard hooks
  576.     _WESetStandardHooks(*hWE);
  577.  
  578.     // create a region to hold the view rectangle
  579.     pWE->viewRgn = NewRgn();
  580.     WELongRectToRect(viewRect, &r);
  581.     RectRgn(pWE->viewRgn, &r);
  582.  
  583.     // initialize the style run array
  584.     (*pWE->hRuns)[1].runStart = 1;
  585.     (*pWE->hRuns)[1].styleIndex = -1;
  586.  
  587.     // initialize the style table
  588.     (*pWE->hStyles)[0].refCount = 1;
  589.  
  590.     // copy text attributes from the active graphics port
  591.     (*pWE->hStyles)[0].info.runStyle.tsFont = pWE->port->txFont;
  592.     (*pWE->hStyles)[0].info.runStyle.tsSize = pWE->port->txSize;
  593.     (*pWE->hStyles)[0].info.runStyle.tsFace = pWE->port->txFace;
  594.     if (BTST(pWE->flags, weFHasColorQD))
  595.     {
  596.         GetForeColor(&(*pWE->hStyles)[0].info.runStyle.tsColor);
  597.     }
  598.     _WEFillFontInfo(pWE->port, &(*pWE->hStyles)[0].info);
  599.  
  600.     // initialize the line array
  601.     if ((err = WECalText(*hWE)) != noErr)
  602.     {
  603.         goto cleanup;
  604.     }
  605.  
  606.     // register with the Text Services Manager
  607.     if ((err = _WERegisterWithTSM(*hWE)) != noErr)
  608.     {
  609.         goto cleanup;
  610.     }
  611.  
  612.     // unlock the WE record
  613.     HUnlock((Handle)*hWE);
  614.  
  615.     // skip clean-up section
  616.     return noErr;
  617.  
  618. cleanup:
  619.     // clean up
  620.     if (pWE != nil)
  621.     {
  622.         _WEForgetHandle((Handle *) &pWE->hText);
  623.         _WEForgetHandle((Handle *) &pWE->hLines);
  624.         _WEForgetHandle((Handle *) &pWE->hStyles);
  625.         _WEForgetHandle((Handle *) &pWE->hRuns);
  626.         if (pWE->viewRgn != nil)
  627.         {
  628.             DisposeRgn(pWE->viewRgn);
  629.         }
  630.     }
  631.     _WEForgetHandle((Handle *)hWE);
  632.  
  633.     return err;
  634. }
  635.  
  636. pascal void _WEResetStyleTable(WEHandle hWE)
  637. {
  638.     WEPtr pWE = *hWE;    // assume WE record is already locked
  639.     SInt32 index;
  640.     StyleTableElement *pTable;
  641.     Boolean saveTableLock;
  642.  
  643.     // sanity check
  644.     if (pWE->hStyles == nil)
  645.         return;
  646.  
  647.     // lock the style table
  648.     saveTableLock = _WESetHandleLock((Handle) pWE->hStyles, true);
  649.     pTable = *pWE->hStyles;
  650.  
  651.     // walk the style table, disposing of all embedded objects referenced there
  652.     index = pWE->nStyles;
  653.     while ( --index >= 0 )
  654.     {
  655.  
  656. #if WASTE_OBJECTS
  657.         if ((pTable->refCount > 0) && (pTable->info.runStyle.tsObject != nil))
  658.         {
  659.             _WEFreeObject(pTable->info.runStyle.tsObject);
  660.         }
  661. #endif
  662.  
  663.         pTable->refCount = 0;
  664.         pTable++;
  665.     };
  666.  
  667.     // unlock the style table
  668.     _WESetHandleLock((Handle) pWE->hStyles, saveTableLock);
  669. }
  670.  
  671. pascal void WEDispose(WEHandle hWE)
  672. {
  673.     WEPtr pWE;
  674.  
  675.     // sanity check: make sure WE isn't nil
  676.     if (hWE == nil)
  677.         return;
  678.  
  679.     // lock the WE record
  680.     HLock((Handle) hWE);
  681.     pWE = *hWE;
  682.  
  683.     // clear the Undo buffer
  684.     WEClearUndo(hWE);
  685.  
  686.     // unregister with the Text Services Manager
  687.     if (pWE->tsmReference != nil)
  688.     {
  689.         DeleteTSMDocument(pWE->tsmReference);
  690.         pWE->tsmReference = nil;
  691.     }
  692.  
  693.     // dispose of the offscreen graphics world
  694.     if (pWE->offscreenPort != nil)
  695.     {
  696.         DisposeGWorld((GWorldPtr)pWE->offscreenPort);
  697.         pWE->offscreenPort = nil;
  698.     }
  699.  
  700. #if WASTE_OBJECTS
  701.     // release all embedded objects we know about
  702.     _WEResetStyleTable(hWE);
  703.  
  704.     // dispose instance-specific object handler table
  705.     _WEForgetHandle((Handle *) &pWE->hObjectHandlerTable);
  706. #endif
  707.  
  708.     // dispose of auxiliary data structures
  709.     _WEForgetHandle((Handle *) &pWE->hText);
  710.     _WEForgetHandle((Handle *) &pWE->hLines);
  711.     _WEForgetHandle((Handle *) &pWE->hStyles);
  712.     _WEForgetHandle((Handle *) &pWE->hRuns);
  713.     DisposeRgn(pWE->viewRgn);
  714.  
  715.     // dispose of the WE record
  716.     DisposeHandle((Handle) hWE);
  717. }
  718.  
  719. pascal OSErr WEUseText(Handle text, WEHandle hWE)
  720. {
  721.     WEPtr pWE;
  722.     RunArrayPtr pRuns;
  723.     LinePtr pLines;
  724.     SInt32 textLength;
  725.     Boolean saveWELock;
  726.  
  727.     // lock the WE record
  728.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  729.     pWE = *hWE;
  730.  
  731.     // stop any ongoing inline session
  732.     WEStopInlineSession(hWE);
  733.  
  734.     // reset modification count and clear undo buffer, if any
  735.     WEResetModCount(hWE);
  736.  
  737.     // reset the style table, disposing of all embedded objects it references
  738.     _WEResetStyleTable(hWE);
  739.  
  740.     // install the text
  741.     _WEForgetHandle(&pWE->hText);
  742.     pWE->hText = text;
  743.     textLength = GetHandleSize(text);
  744.     pWE->textLength = textLength;
  745.  
  746.     // reset the run array
  747.     SetHandleSize((Handle) pWE->hRuns, 2 * sizeof(RunArrayElement));
  748.     pWE->nRuns = 1;
  749.     pRuns = *pWE->hRuns;
  750.     pRuns[1].runStart = textLength + 1;
  751.     pRuns[1].styleIndex = -1;
  752.  
  753.     // fix the refCount of the style table entry referenced by the only run
  754.     (*pWE->hStyles)[pRuns[0].styleIndex].refCount = 1;
  755.  
  756.     // reset the line array
  757.     SetHandleSize((Handle) pWE->hLines, 2 * sizeof(LineRec));
  758.     pWE->nLines = 1;
  759.     pLines = *pWE->hLines;
  760.     _WEBlockClr(pLines, 2 * sizeof(LineRec));
  761.     pLines[1].lineStart = textLength;
  762.  
  763.     // reset several fields of the WE record
  764.     pWE->selStart = 0;
  765.     pWE->selEnd = 0;
  766.     pWE->firstByte = 0;
  767.     pWE->clickCount = 0;
  768.     pWE->tsmAreaStart = kInvalidOffset;
  769.     pWE->tsmAreaEnd = kInvalidOffset;
  770.     pWE->dragCaretOffset = kInvalidOffset;
  771.  
  772.     // recalculate and redraw everything
  773.     // err = _WERedraw(0, LONG_MAX, hWE);
  774.  
  775.     // unlock the WE record
  776.     _WESetHandleLock((Handle) hWE, saveWELock);
  777.  
  778.     return noErr;
  779. }
  780.  
  781. pascal SInt16 WEFeatureFlag(SInt16 feature, SInt16 action, WEHandle hWE)
  782. {
  783.     WEPtr pWE = *hWE;
  784.     SInt16 status;
  785.  
  786.     // get current status of the specified feature
  787.     status = BTST(pWE->features, feature) ? weBitSet : weBitClear;
  788.  
  789.     // if action is weBitToggle, invert flag
  790.     if (action == weBitToggle)
  791.         action = 1 - status;
  792.  
  793.     // reset flag according to action
  794.     if (action == weBitClear)
  795.     {
  796.         BCLR(pWE->features, feature);
  797.     }
  798.     else if (action == weBitSet)
  799.     {
  800.         BSET(pWE->features, feature);
  801.     }
  802.  
  803.     // return old status
  804.     return status;
  805. }
  806.